#include "hamiltonfunctor.h"


const string HamiltonFunctor::biassymbol = "Bias";

HamiltonFunctor::HamiltonFunctor(System *s, const rule::list &opts) : sys(s), bias(0.)
{
	const size_t rulesize = opts.size();
	for(size_t r = 0; r < rulesize; r++)
	{
		if(!opts[r].first.isSymbolType())
			continue;
		
		symbol sym = opts[r].first.toSymbol();
		variant var = opts[r].second;

		if(sym.name() == biassymbol)
			bias = (var.isNumericType()) ? var.toDouble() : 0.;
	}
}

complex HamiltonFunctor::getHamiltonElement(const Bond &b, arma::vec k, double v)
{
	double phase = arma::dot(k,b.getXyz());
	complex c(cos(phase),sin(phase));

	if(b.getCouplingType() == Bond::SameAtom)
	{
		if(b.getOrigin()->getType() == Atom::dimer)
			return sys->epsilon + sys->Delta + ((b.getOrigin()->h() % 2) ? v/2. : -v/2. );
		else
			return sys->epsilon + ((b.getOrigin()->h() % 2) ? v/2. : -v/2. );
	}
	else if(b.getCouplingType() == Bond::NearestNeighbours)
		return sys->gamma0*c;
	else if(b.getCouplingType() == Bond::DimerNeighbours)
		return sys->gamma1*c;
	else if(b.getCouplingType() == Bond::NonDimerNeighbours)
		return sys->gamma3*c;
	else if(b.getCouplingType() == Bond::DimerNextNeighbours)
		return sys->gamma4*c;

	return 0.;
}

arma::sp_cx_mat HamiltonFunctor::getTransferIntegral(int id, arma::vec k) { return getTransferIntegral(id, k, bias); }
arma::sp_cx_mat HamiltonFunctor::getTransferIntegral(int id, arma::vec k, double v)
{
	Unit* unitref = sys->getUnit(id);
	if(!unitref)
		return arma::sp_cx_mat();

	const size_t elementsize = unitref->getBonds().size();

	arma::cx_vec values;
	values.set_size(elementsize);
	values.fill(arma::fill::zeros);

	for(size_t e = 0; e < elementsize; e++)
	{
		size_t bondsize = unitref->getBonds()[e].size();
		for(size_t b = 0; b < bondsize; b++)
			values(e) += getHamiltonElement(unitref->getBonds()[e][b], k, v);
	}

	return arma::sp_cx_mat(unitref->getBondsLocations(),values,false);
}